﻿using Microsoft.Office.Server.Search.Administration;
using Microsoft.Office.Server.Search.Administration.Query;
using Microsoft.Office.Server.Search.Query.Rules;
using SPSDeploy.Extensions.Controllers;
using SPSDeploy.Extensions.Extensions;
using System.Collections.Generic;
using System.Xml.Linq;

namespace SPSDeploy.Extensions.Modules.Compare
{
    /// <summary>
    /// Search proxy compare module
    /// </summary>
    internal class SearchProxyModule : SearchModule
    {

        /// <summary>
        /// Initialization
        /// </summary>
        /// <param name="controller"></param>
        internal SearchProxyModule(BaseController controller)
            : base(controller)
        {
        }

        /// <summary>
        /// Execute module
        /// </summary>
        /// <param name="compare"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        internal override XElement Execute(XElement compare, XElement parent)
        {
            XElement proxy = new XElement("serviceApplicationProxy", new XAttribute("name", compare.Attribute("name").Value), new XAttribute("type", compare.Attribute("type").Value));
            SearchServiceApplicationProxy serviceApplicationProxy = (SearchServiceApplicationProxy)ServiceApplicationProxyExtension.GetServiceApplicationProxy(compare.Attribute("name").Value, compare.Attribute("type").Value);
            if (serviceApplicationProxy != null)
            {
                FederationManager manager = new FederationManager(serviceApplicationProxy);
                XElement search = (XElement)compare.FirstNode;
                XElement result = CompareSearchApplicationProxy(search, serviceApplicationProxy);
                CompareResultSources(search, result, serviceApplicationProxy, manager);
                CompareResultTypes(search, result, ResultTypesExtension.GetOwners(serviceApplicationProxy), manager, new ResultItemTypeManager(serviceApplicationProxy));
                CompareQueryRules(search, result, QueryRulesExtension.GetOwners(serviceApplicationProxy), manager, new QueryRuleManager(serviceApplicationProxy));
                CompareManagedProperties(search, result, serviceApplicationProxy);
                Tools.RollupElement(proxy, result);
                controller.OnProgressMessage(string.Format("Search service application '{0}' information compared.", compare.Attribute("name").Value));
            }
            Tools.RollupElement(parent, proxy);
            return proxy;
        }

        #region Search Application Proxy
        /// <summary>
        /// Compare search application proxy
        /// </summary>
        /// <param name="search"></param>
        /// <param name="proxy"></param>
        /// <returns></returns>
        private XElement CompareSearchApplicationProxy(XElement search, SearchServiceApplicationProxy proxy)
        {
            XElement result = new XElement("searchServiceApplicationProxy");
            XElement updates = GetUpdatesElement();
            Compare(updates, search.Attribute("mergeWithDefaultPartition"), proxy.MergeWithDefaultPartition);
            Tools.RollupElement(result, updates);
            return result;
        }
        #endregion

        #region Result Sources
        /// <summary>
        /// Compare result sources
        /// </summary>
        /// <param name="search"></param>
        /// <param name="parent"></param>
        /// <param name="proxy"></param>
        /// <param name="manager"></param>
        private void CompareResultSources(XElement search, XElement parent, SearchServiceApplicationProxy proxy, FederationManager manager)
        {
            CompareResultSources(search, parent, ResultSourcesExtension.GetOwners(proxy), manager);
            CompareDefaultResultSources(search, parent, ResultSourcesExtension.GetDefaultResultSourceOwners(proxy), manager);
        }
        #endregion

        #region Managed Properties
        /// <summary>
        /// Compare managed properties
        /// </summary>
        /// <param name="search"></param>
        /// <param name="parent"></param>
        /// <param name="proxy"></param>
        private void CompareManagedProperties(XElement search, XElement parent, SearchServiceApplicationProxy proxy)
        {
            Dictionary<int, SearchObjectOwner> owners = new Dictionary<int, SearchObjectOwner>();
            List<ManagedPropertyInfo> items = new List<ManagedPropertyInfo>();
            foreach (SearchObjectOwner owner in ManagedPropertiesExtension.GetOwners(proxy))
                foreach (ManagedPropertyInfo item in proxy.GetManagedProperties(null, int.MaxValue, owner))
                    if (!owners.ContainsKey(item.Pid))
                    {
                        items.Add(item);
                        owners.Add(item.Pid, owner);
                    }
            CompareManagedProperties(search, parent, items, owners);
        }
        #endregion

    }
}